cmake_minimum_required(VERSION 3.15)
project(kvstore)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage -O3 -g -ggdb -fopenmp -fpic -pthread -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fprofile-arcs -ftest-coverage -g -ggdb -fopenmp -fpic")
set(protobuf_ROOT "/usr/local")
set(gRPC_ROOT "/usr/local")
set(abseil_ROOT "/usr/local")

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY  ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY  ${CMAKE_CURRENT_SOURCE_DIR}/bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY  ${CMAKE_CURRENT_SOURCE_DIR}/bin)

# 设置存储后端
set(FS_STRATEGY "POSIX" CACHE STRING "Select filesystem strategy: [POSIX|THREEFS|...]")
set_property(CACHE FS_STRATEGY PROPERTY STRINGS POSIX THREEFS)

# 设置昇腾环境
set(DEVICE "NPU" CACHE STRING "Select device: [GPU|NPU|NODEV|...]")
set_property(CACHE DEVICE PROPERTY STRINGS NPU GPU NODEV)

if (DEVICE STREQUAL "GPU")
    add_compile_definitions(USE_GPU)
    message(STATUS "Selected device:GPU")
    set(CUDA_DIR "/usr/local/cuda")
    set(CUDA_INC_DIR "/usr/local/cuda/targets/x86_64-linux/include/")
    find_package(CUDA REQUIRED)
    find_package(CUDAToolkit REQUIRED)
elseif (DEVICE STREQUAL "NPU")
    add_compile_definitions(USE_NPU)
    message(STATUS "Selected device:NPU")
elseif (DEVICE STREQUAL "NODEV")
    add_compile_definitions(USE_DRAM)
    message(STATUS "No Selected device")
else()
    message(FATAL_ERROR "Invalid device: ${DEVICE}")
endif()

# 定义所有参数的默认值
# 可以用环境变量覆盖
# 定义生成目录
set(DEFAULT_MOUNT_POINT "/data/yangxianpku/storage" CACHE STRING "Default mount path")
set(DEFAULT_BLOCK_SIZE 33554432 CACHE STRING "Default block size in bytes")   # 32MB
set(DEFAULT_LOG_PATH "/var/log/KVStore/" CACHE STRING "Default LOG path")
set(DEFAULT_LOG_LEVEL "INFO" CACHE STRING "Default LOG LEVEL")
set(DEFAULT_CLIENT_PORT "50051" CACHE STRING "Default Client Port")
set(DEFAULT_LAYOUT "NHD" CACHE STRING "Default Layout")
if (BUILD_TEST)
    set(DEFAULT_MEMPOOL_SIZE 17179869184 CACHE STRING "Default memory pool size in bytes")  # 16GB
    set(DEFAULT_GET_THREADPOOL_SIZE 1 CACHE STRING "Default GET threadpool size")
    set(DEFAULT_PUT_THREADPOOL_SIZE 1 CACHE STRING "Default PUT threadpool size")
else()
    set(DEFAULT_MEMPOOL_SIZE 17179869184 CACHE STRING "Default memory pool size in bytes")  # 16GB
    set(DEFAULT_GET_THREADPOOL_SIZE 16 CACHE STRING "Default GET threadpool size")
    set(DEFAULT_PUT_THREADPOOL_SIZE 4 CACHE STRING "Default PUT threadpool size")
endif()

# 将参数转换为编译宏定义
function(add_safe_definition name value type)
    if(type STREQUAL "STRING")
        string(REPLACE "\"" "\\\"" escaped_value "${value}")
        add_compile_definitions(${name}="${escaped_value}")
    else()
        add_compile_definitions(${name}=${value})
    endif()
endfunction()

add_safe_definition(DEFAULT_MEMPOOL_SIZE ${DEFAULT_MEMPOOL_SIZE} NUMBER)
add_safe_definition(DEFAULT_BLOCK_SIZE ${DEFAULT_BLOCK_SIZE} NUMBER)
add_safe_definition(DEFAULT_GET_THREADPOOL_SIZE ${DEFAULT_GET_THREADPOOL_SIZE} NUMBER)
add_safe_definition(DEFAULT_PUT_THREADPOOL_SIZE ${DEFAULT_PUT_THREADPOOL_SIZE} NUMBER)
add_safe_definition(DEFAULT_MOUNT_POINT "${DEFAULT_MOUNT_POINT}" STRING)
add_safe_definition(DEFAULT_LOG_PATH "${DEFAULT_LOG_PATH}" STRING)
add_safe_definition(DEFAULT_LOG_LEVEL "${DEFAULT_LOG_LEVEL}" STRING)
add_safe_definition(DEFAULT_CLIENT_PORT "${DEFAULT_CLIENT_PORT}" STRING)
add_safe_definition(DEFAULT_LAYOUT "${DEFAULT_LAYOUT}" STRING)

if (BUILD_TEST)
add_compile_definitions(IGNORE_PYBIND)
endif()

if(DYNAMO)
    add_compile_definitions(USE_DYNAMO)
    message(STATUS "Selected Dynamo Publisher")
endif()

# 导入依赖库
find_package(protobuf REQUIRED HINTS ${Protobuf_ROOT})
include_directories(${PROTOBUF_INCLUDE_DIRS})

find_package(gRPC REQUIRED HINTS ${gRPC_ROOT})
find_package(absl REQUIRED)
find_package(Threads REQUIRED)
find_package(pybind11 REQUIRED)

# 指定 proto 文件路径
set(PROTOS
        ${CMAKE_CURRENT_LIST_DIR}/proto/kvcache.proto
        ${CMAKE_CURRENT_LIST_DIR}/proto/kvctrl_api.proto
)
add_library(proto-objects OBJECT 
            ${CMAKE_CURRENT_LIST_DIR}/proto/kvcache.proto 
            ${CMAKE_CURRENT_LIST_DIR}/proto/kvctrl_api.proto
        )
target_link_libraries(proto-objects PUBLIC protobuf::libprotobuf)

set(PROTO_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/proto_generated")
file(MAKE_DIRECTORY ${PROTO_BINARY_DIR})
target_include_directories(proto-objects PUBLIC "$<BUILD_INTERFACE:${PROTO_BINARY_DIR}>")

# 设置生成的源文件路径
protobuf_generate(
        TARGET proto-objects
        PROTOS ${PROTOS}
        PROTOC_OUT_DIR ${PROTO_BINARY_DIR}
)

protobuf_generate(
        TARGET proto-objects
        LANGUAGE grpc
        GENERATE_EXTENSIONS .grpc.pb.h .grpc.pb.cc
        PLUGIN "protoc-gen-grpc=\$<TARGET_FILE:gRPC::grpc_cpp_plugin>"
        PROTOS ${PROTOS}
        PROTOC_OUT_DIR ${PROTO_BINARY_DIR}
)

add_subdirectory(src)
if (BUILD_TEST)
add_subdirectory(test)
endif()
